﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq.Expressions;

namespace Callisto.Infrastructure
{
    public class NotifyPropertyChangedBase : INotifyPropertyChanged
    {
        #region Fields
        private readonly FastSmartWeakEvent<PropertyChangedEventHandler> _event = new FastSmartWeakEvent<PropertyChangedEventHandler>();
        #endregion Fields

        #region Events
        public event PropertyChangedEventHandler PropertyChanged
        {
            add { if (_event != null) _event.Add(value); }
            remove { if (_event != null) _event.Remove(value); }
        }
        #endregion Events

        #region Methods
        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            _event.Raise(this, e);
        }

        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyExpression">The property expression.</param>
        protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var lambda = propertyExpression as LambdaExpression;
            MemberExpression memberEx;
            if (lambda.Body is UnaryExpression)
                memberEx = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
            else
                memberEx = lambda.Body as MemberExpression;

            OnPropertyChanged(memberEx.Member.Name);
        }

        /// <summary>
        /// Registers <paramref name="collectionChanged"/> with <paramref name="newCollection"/> to forward events.
        /// </summary>
        /// <remarks>
        /// <paramref name="collectionChanged"/> must be passed in; else FastSmartWeakEvent 
        /// might consider it a dead target and remove them without notice.
        /// </remarks>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="oldCollection">The old collection.</param>
        /// <param name="newCollection">The new collection.</param>
        /// <param name="collectionChanged">The collection changed handler.</param>
        protected void OnCollectionChanged<TItem>(ObservableCollection<TItem> oldCollection, ObservableCollection<TItem> newCollection, NotifyCollectionChangedEventHandler collectionChanged)
        {
            if (oldCollection != null)
                oldCollection.CollectionChanged -= collectionChanged;
            if (newCollection != null)
                newCollection.CollectionChanged += collectionChanged;
        }

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="propertyNames">The property names.</param>
        protected void OnPropertyChanged(params string[] propertyNames)
        {
            foreach (var propertyName in propertyNames)
            {
                OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion Methods
    }
}